package net.borderwars.userserver;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.RemoteException;
import java.util.List;

/**
 * User: hubbard
 * Date: Mar 6, 2006
 * Time: 8:57:39 PM
 */
public class ObjectRef implements Serializable {
    transient private static Integer gid = 0;
    private Integer id = gid++;
    private Class interfaces[];
    private MethodCallProvider client;

    public ObjectRef(final List<Class> these) {
        interfaces = new Class[these.size()];
        int x = 0;
        for (Class aClass : these) {
            interfaces[x++] = aClass;
        }
    }

    public Integer getId() {
        return id;
    }

    public Class<?>[] getInterfaces() {
        return (interfaces);

    }

    public Object makeProxy() {
        InvocationHandler ih = new Handler(this);
        Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, ih);
        return (o);
    }

    public void setClient(MethodCallProvider c) {
        this.client = c;
    }

    public class Handler implements InvocationHandler {

        private ObjectRef or;

        public Handler(ObjectRef or) {
            this.or = or;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            assert (client != null);

            System.out.println("Invoking " + method.getName() + "(" + args + ")");
            Class types[] = null;
            if (args != null && args.length != 0) {
                types = new Class[args.length];
                int idx = 0;
                for (Object o : args) {
                    types[idx++] = o.getClass();
                }
            }
            Invocation i = new Invocation(method.getName(), types, args, or.getId());
            InvocationResult ir = client.makeMethodCall(i);
            if (ir.hadException()) {
                throw new RemoteException("Error occured on the serverside", ir.getException());
            }
            Object o = ir.getResult();
            if (o instanceof ObjectRef) {
                ObjectRef objectRef = (ObjectRef) o;
                o = objectRef.makeProxy();
            }
            if (o instanceof VOID) {
                return (null);
            }
            return o;
        }
    }

}
